package cn.tedu.hotel.service.impl;

import cn.tedu.hotel.ex.ServiceException;
import cn.tedu.hotel.mapper.AlbumRoomMapper;
import cn.tedu.hotel.mapper.RoomMapper;
import cn.tedu.hotel.mapper.RoomTypeMapper;
import cn.tedu.hotel.mapper.CategoryMapper;
import cn.tedu.hotel.pojo.dto.RoomAddNewDTO;
import cn.tedu.hotel.pojo.entity.Room;
import cn.tedu.hotel.pojo.entity.RoomType;
import cn.tedu.hotel.pojo.entity.Category;
import cn.tedu.hotel.pojo.vo.RoomListItemVO;
import cn.tedu.hotel.pojo.vo.RoomStandardVO;
import cn.tedu.hotel.pojo.vo.CategoryStandardVO;
import cn.tedu.hotel.repository.IRoomRedisRepository;
import cn.tedu.hotel.service.IRoomService;
import cn.tedu.hotel.web.ServiceCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Set;

/**
 *   处理房间数据的业务接口
 */
@Slf4j
@Service
public class RoomServiceImpl implements IRoomService, ServiceCode {

    @Autowired
    private RoomMapper roomMapper;
    @Autowired
    private CategoryMapper categoryMapper;
    @Autowired
    private RoomTypeMapper roomTypeMapper;
    @Autowired
    private AlbumRoomMapper albumRoomMapper;
    @Autowired
    private IRoomRedisRepository roomRedisRepository;

    public RoomServiceImpl(){
        log.debug("创建业务对象：RoomServiceImpl");
    }

    @Override
    public void addNew(RoomAddNewDTO roomAddNewVO) {
        log.debug("开始处理【添加房间】业务，参数：{}",roomAddNewVO);
        // 获取需要插入的数据的名字
        String name = roomAddNewVO.getName();
        // 调用Mapper对象的int countByName(String name)方法统计此名称的类别的数量
        int count = roomMapper.countByName(name);
        //判断统计结果是否大于0
        if (count > 0){
            // 是：房间名称已经存在，抛出RuntimeException异常
            String message = "添加房间失败！品牌名称【" + name + "】已存在！";
            log.warn(message);
            throw new ServiceException(ERR_CONFLICT, message);
        }

        // 获取当前时间
        LocalDateTime now = LocalDateTime.now();

            //创建room对象
            Room room = new Room();
            //补全room对象的属性值
            BeanUtils.copyProperties(roomAddNewVO, room);
            room.setGmtCreate(now);
            room.setGmtModified(now);
        {
            //执行插入
            log.debug("即将向数据库插入房间数据：{}", room);
            int rows = roomMapper.insert(room);
            //判断受响应结果是否有误
            if (rows != 1) {
                String message = "添加房间失败！服务器忙，请稍后再次尝试！";
                log.warn(message);
                throw new ServiceException(ERR_INSERT, message);
            }
        }

        // 向房间与类型管理表中插入数据
        {
            Long roomId = room.getId();
            Long typeId = roomAddNewVO.getTypeId();

            RoomType roomType = new RoomType();
            roomType.setRoomId(roomId);
            roomType.setTypeId(typeId);
            roomType.setGmtCreate(now);
            roomType.setGmtModified(now);
            int rows = roomTypeMapper.insert(roomType);
            //判断受响应结果是否有误
            if (rows != 1){
                String message = "添加房间失败！服务器忙，请稍后再次尝试！";
                log.warn(message);
                throw new ServiceException(ERR_INSERT, message);
            }
        }

        // 修改房间数量
        {
            Long typeId = roomAddNewVO.getTypeId();

            CategoryStandardVO standardById = categoryMapper.getStandardById(typeId);
            if (standardById == null){
                String message = "房间类型不存在，无法修改";
                log.debug(message);
                throw new ServiceException(ERR_NOT_FOUND, message);
            }

            Integer total = standardById.getTotal()+1;
            Integer surplus = standardById.getSurplus()+1;
            Category category = new Category();
            category.setId(typeId);
            category.setTotal(total);
            category.setSurplus(surplus);
            categoryMapper.update(category);
        }


    }

    @Override
    public void deleteById(Long id) {
        log.debug("开始处理【删除房间】的业务，参数：{}", id);
        // 检查尝试删除的房间是否存在
        {
            Object queryResult = roomMapper.getStandardById(id);
            if (queryResult == null) {
                throw new ServiceException(ERR_NOT_FOUND, "删除房间失败，尝试访问的数据不存在！");
            }
        }

        // 检查是否关联房间相册
        {
            int count = albumRoomMapper.countByRoomId(id);
            if (count > 0){
                throw new ServiceException(ERR_DELETE,"删除失败，房间与房间类型存在关联");
            }
        }

        //检查房间是否关联房间类型
        {
            int count = roomTypeMapper.countByRoomId(id);
            if (count > 0){
                throw new ServiceException(ERR_DELETE,"删除失败，房间与房间类型存在关联");
            }
        }

        // 执行删除
        log.debug("即将删除id为{}房间的数据", id);
        int rows = roomMapper.deleteById(id);
        if (rows != 1) {
            throw new ServiceException(ERR_DELETE, "删除房间失败，服务器忙，请稍后再次尝试！");
        }
        log.debug("删除完成！");



        //删除Redis中相应的房间缓存数据
        log.debug("删除缓存中id={}的房间数据",id);
        roomRedisRepository.deleteItem(id);
    }

    @Override
    public void setEnable(Long id) {
        log.debug("开始处理【启用房间】的业务：id={}",id);
        // 根据id查询房间数据
        RoomStandardVO queryResult = roomMapper.getStandardById(id);
        // 判断是否为null
        if (queryResult == null){
            // 是：数据不存在，抛出异常
            String message = "启用失败，访问数据不存在";
            log.warn(message);
            throw new ServiceException(ERR_NOT_FOUND,message);
        }

        // 判断查询结果中的enable是否为1
        if (queryResult.getEnable() == 1){
            // 是：状态重复，抛出异常
            String message = "启用失败，该房间已经是启用状态";
            log.warn(message);
            throw new ServiceException(ERR_CONFLICT,message);
        }

        // 创建对象，并设置状态值
        Room room = new Room();
        room.setId(id);
        room.setEnable(1);
        //执行更新，获取返回值
        int rows = roomMapper.update(room);
        //判断返回值是否有误
        if (rows != 1){
            String message = "启用房间失败，服务器繁忙，请稍后再试";
            log.warn(message);
            throw new ServiceException(ERR_UPDATE,message);
        }
    }

    @Override
    public void setDisable(Long id) {
        log.debug("开始处理【禁用房间】的业务：id={}",id);
        // 根据id查询房间数据
        RoomStandardVO queryResult = roomMapper.getStandardById(id);
        // 判断是否为null
        if (queryResult == null){
            // 是：数据不存在，抛出异常
            String message = "禁用失败，访问数据不存在";
            log.warn(message);
            throw new ServiceException(ERR_NOT_FOUND,message);
        }

        // 判断查询结果中的enable是否为0
        if (queryResult.getEnable() == 0){
            // 是：状态重复，抛出异常
            String message = "禁用失败，该房间已经是启用状态";
            log.warn(message);
            throw new ServiceException(ERR_CONFLICT,message);
        }

        // 创建对象，并设置状态值
        Room room = new Room();
        room.setId(id);
        room.setEnable(0);
        //执行更新，获取返回值
        int rows = roomMapper.update(room);
        //判断返回值是否有误
        if (rows != 1){
            String message = "禁用房间失败，服务器繁忙，请稍后再试";
            log.warn(message);
            throw new ServiceException(ERR_UPDATE,message);
        }
    }

    @Override
    public void setLeisure(Long id) {
        log.debug("开始处理【将房间设置为空闲状态】的业务，房间id={}",id);
        // 根据id查询房间数据
        RoomStandardVO queryResult = roomMapper.getStandardById(id);
        // 判断是否为null
        if (queryResult == null){
            // 是：数据不存在，抛出异常
            String message = "设置房间状态空闲失败，访问数据不存在";
            log.warn(message);
            throw new ServiceException(ERR_NOT_FOUND,message);
        }

        // 判断查询结果中的state是否为0
        if (queryResult.getState() == 0){
            // 是：状态重复，抛出异常
            String message = "设置房间状态空闲失败，该房间类型已经是启用状态";
            log.warn(message);
            throw new ServiceException(ERR_CONFLICT,message);
        }

        // 创建对象，并设置状态值
        Room room = new Room();
        room.setId(id);
        room.setState(0);
        //执行更新，获取返回值
        int rows = roomMapper.update(room);
        //判断返回值是否有误
        if (rows != 1){
            String message = "设置房间状态空闲失败，服务器繁忙，请稍后再试";
            log.warn(message);
            throw new ServiceException(ERR_UPDATE,message);
        }

    }

    @Override
    public void setOccupy(Long id) {
        log.debug("开始处理【将房间设置为占用状态】的业务，房间id={}",id);
        // 根据id查询房间数据
        RoomStandardVO queryResult = roomMapper.getStandardById(id);
        // 判断是否为null
        if (queryResult == null){
            // 是：数据不存在，抛出异常
            String message = "设置房间状态占用失败，访问数据不存在";
            log.warn(message);
            throw new ServiceException(ERR_NOT_FOUND,message);
        }

        // 判断查询结果中的state是否为1
        if (queryResult.getState() == 1){
            // 是：状态重复，抛出异常
            String message = "设置房间状态占用失败，该房间类型已经是启用状态";
            log.warn(message);
            throw new ServiceException(ERR_CONFLICT,message);
        }

        // 创建对象，并设置状态值
        Room room = new Room();
        room.setId(id);
        room.setState(1);
        //执行更新，获取返回值
        int rows = roomMapper.update(room);
        //判断返回值是否有误
        if (rows != 1){
            String message = "设置房间状态占用失败，服务器繁忙，请稍后再试";
            log.warn(message);
            throw new ServiceException(ERR_UPDATE,message);
        }

    }

    @Override
    public void setAbnormal(Long id) {
        log.debug("开始处理【将房间设置为异常状态】的业务，房间id={}",id);
        // 根据id查询房间数据
        RoomStandardVO queryResult = roomMapper.getStandardById(id);
        // 判断是否为null
        if (queryResult == null){
            // 是：数据不存在，抛出异常
            String message = "设置房间状态异常失败，访问数据不存在";
            log.warn(message);
            throw new ServiceException(ERR_NOT_FOUND,message);
        }

        // 判断查询结果中的state是否为2
        if (queryResult.getState() == 2){
            // 是：状态重复，抛出异常
            String message = "设置房间状态异常失败，该房间类型已经是启用状态";
            log.warn(message);
            throw new ServiceException(ERR_CONFLICT,message);
        }

        // 创建对象，并设置状态值
        Room room = new Room();
        room.setId(id);
        room.setState(2);
        //执行更新，获取返回值
        int rows = roomMapper.update(room);
        //判断返回值是否有误
        if (rows != 1){
            String message = "设置房间状态异常失败，服务器繁忙，请稍后再试";
            log.warn(message);
            throw new ServiceException(ERR_UPDATE,message);
        }

    }


    @Override
    public RoomStandardVO getStandardById(Long id) {
        log.debug("开始处理【根据房间id={}查询房间详细信息】的业务",id);
        log.debug("开始尝试从Redis中获取id={}的房间数据",id);
        // 根据房间id从Redis中获取数据
        RoomStandardVO roomStandardVO = roomRedisRepository.get(id);
        //判断结果是否不为null
        if (roomStandardVO != null){
            // 是： 数据存在， 直接返回
            log.debug("从Redis中获取到的有效结果，将返回：{}",roomStandardVO);
            return roomStandardVO;
        }

        log.debug("Redis中没有匹配的数据，将从数据库中查询");
        // redis中没有数据，调用mapper的方法 查询数据库中数据
        RoomStandardVO queryResult = roomMapper.getStandardById(id);
        // 判断结果是否为null
        if (queryResult == null){
            // 是：没有要查询的数据，抛出异常
            String message = "查询房间详情失败，尝试访问的数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        //将查询的结果存入Redis，并返回结果
        log.debug("从数据库中查询到有效结果！数据：{}",queryResult);
        roomRedisRepository.put(queryResult);
        return queryResult;

    }


    @Override
    public List<RoomListItemVO> listRoom() {
        log.debug("开始处理【查询房间列表】的业务");
        // 从Redis中读取房间列表
        List<RoomListItemVO> rooms = roomRedisRepository.getList();
        log.debug("从Redis中读到房间列表：{}",rooms);
        //如果读到有效列表，表示Redis中存在
        if (rooms.size() > 0){
            // 将结果直接返回
            log.debug("在Redis中读到有效的房间列表，即将直接返回：{}",rooms);
            return rooms;
        }

        //如果读到的结果为空集，表示Redis中没有此数据
        //调用mapper去数据库中查询，并存入Redis，并返回
        List<RoomListItemVO> roomListItemVOS = roomMapper.listRoom();
        roomRedisRepository.putList(roomListItemVOS);
        log.debug("在数据库中查到房间列表数据：{}，存入Redis中，并返回",roomListItemVOS);
        return roomListItemVOS;
    }

    @Override
    public void loadRoomToCache() {
        log.debug("开始处理【加载房间缓存到缓存中】");
        // 删除原有的房间缓存数据
        Set<String> keys = roomRedisRepository.getAllKeys();
        roomRedisRepository.deleteAll(keys);

        //调用mapper查询房间列表
        List<RoomListItemVO> listRoom = roomMapper.listRoom();
        //调用RedisRepository将房间列表写入到缓存中
        roomRedisRepository.putList(listRoom);

        //遍历mapper的查询结果，根据id查询每一个房间数据，然后调用RedisRepository将数据写入到缓存中
        for (RoomListItemVO room : listRoom){
            RoomStandardVO roomStandardVO = roomMapper.getStandardById(room.getId());
            roomRedisRepository.put(roomStandardVO);
        }

    }

}
